/*
Implementación concurrente en lenguaje JAVA del problema del Barbero Durmiente. 
Vea http://es.wikipedia.org/wiki/Problema_del_barbero_durmiente

Copyright © 2009 Martín Gaitán  http://nqnwebs.com

Este programa es software libre: usted puede redistribuirlo y/o modificarlo conforme a los términos de la Licencia Pública General de GNU publicada por
la Fundación para el Software Libre, ya sea la versión 3 de esta Licencia o (a su elección) cualquier versión posterior.

Este programa se distribuye con el deseo de que le resulte útil, pero SIN GARANTÍAS DE NINGÚN TIPO; ni siquiera con las garantías implícitas de COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO DETERMINADO.  Para más información, consulte la Licencia Pública General de GNU.

Junto con este programa, se debería incluir una copia de la Licencia Pública General de GNU.
De no ser así, ingrese en <http://www.gnu.org/licenses/>.
*/



/* 
Para ejecutar este programa, compile todos los fuentes y ejecute BarberoDurmiente

javac *.java
java BarberoDurmiente
*/



class Barbero extends Thread {

   private Salon s;

   public Barbero(Salon s) {
      this.s = s;
   }

   public void run() {
      while (true)
         quiereCortar();
   }
   
   public void quiereCortar() {
      System.out.println("el Barbero está libre, esperando por un cliente");
      s.cliente.down(); // esperando un cliente. 
      s.mutex.down();    //silla libre
      s.esperar--;        // decrementa cola de cliente
      s.barbero.up();      // pemirte al siguiente cliente
      System.out.println("El Barbero sentó a un cliente en su silla  (Sillas ocupadas: " + s.esperar + "/" + s.numSillas + ")");
      s.mutex.up();   // silla ocupada
      System.out.println("Barbero cortando cabello");
      s.cortar.down();   // cortando
   }
   
   
}

class Cliente extends Thread {

    private Salon s;
    private int i;

   public Cliente(Salon s, int i) {
      this.s = s;
      this.i = i;
   }

   public void run() {
      while (true) {
         System.out.println("Al Cliente " + i + " le está creciendo el cabello ");
            try {
                sleep((int)(Math.random() * 50000));  // durante tiempo aleatorio 
            } catch (InterruptedException e) { }
         System.out.println("Cliente " + i + " necesita un corte de cabello");
         quiereCorte();
      }
   }
   

   public void quiereCorte() {
      s.mutex.down();
      if (s.esperar < s.numSillas) {
          s.esperar++;  // uno o más clientes esperando
          System.out.println("El Cliente " + i + " está esperando en la sala. (Sillas ocupadas: " + s.esperar + "/" + s.numSillas + ")");
          s.cliente.up(); // incremento cliente en espera
          s.mutex.up();   
          s.barbero.down();  // espera la silla del barbero
          System.out.println("Cliente " + i + " está recibiendo su corte de cabello");
          try {
             Thread.sleep((int)(Math.random() * 25000));   //tiempo que demora el corte 
          } catch (InterruptedException e) { }
            System.out.println("Terminó el corte para el Cliente " + i);
          s.cortar.up();   // terminó el corte
      } else {
         System.out.println("Cliente " + i + " se retira, la sala está llena");
         s.mutex.up();
      }
   }   
   
}

class Salon {
    public int numSillas, esperar;
    public Semaphore cliente, barbero, cortar;
    public BinarySemaphore mutex;

    public Salon(int numSillas) {
        this.numSillas = numSillas;
        cliente = new Semaphore(0);   // cuenta clientes en espera
        barbero = new Semaphore(0);      // señala si la silla del barbero está libre
        cortar = new Semaphore(0);     // señala cuando se terminó el corte
        mutex = new BinarySemaphore(1);   // mutex que señala la exclusion mutua  
   }

}

class BarberoDurmiente {

   public static void main(String[] args) {

       int numSillas = 4;
       int numClientes = 10;
       Salon s = new Salon(numSillas);
       new Barbero(s).start();
       for(int i = 0; i < numClientes; i++)
           new Cliente(s,i).start();
   }
}

